package main

import (
	"fmt"
	"log"
	"math/rand"
	"sync"
)

/**
Pool: 创建一个临时对象池，缓存一组对象用于重复利用，以此减少内存分配和降低gc的压力
应用场景：用于连接池(grpc、客户端、网络连接等)
注意事项：
1、用于缓存一些创建成本较高，使用比较频繁的对象
2、Pool的长度默认为机器cpu线程数
3、存储在Pool中的对象随时可能在不被通知的情况下被回收
4、没有什么创建成本的对象不建议使用对象池
*/
func main() {
	target := "192.168.1.1"
	pool, err := GetPool(target)
	if err != nil {
		log.Fatal(err)
	}

	wg := sync.WaitGroup{}
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := 0; j < 2; j++ {
				conn := pool.Get()
				fmt.Println("conn.id:", conn.Id)
				pool.Put(conn)
			}
		}()
	}
	wg.Wait()
	/**
	conn.id: 5577006791947779410
	conn.id: 8674665223082153551
	conn.id: 5577006791947779410
	conn.id: 8674665223082153551
	conn.id: 4037200794235010051
	conn.id: 4037200794235010051
	conn.id: 3916589616287113937
	conn.id: 3916589616287113937
	conn.id: 6129484611666145821
	conn.id: 6129484611666145821
	*/
	// 可以发现每2条可以拿到一个相同的id, 也就实现了pool的重复利用
}

const (
	OFF = 0
	ON  = 1
)

type Conn struct {
	Id     int64
	Target string
	Status int
}

// Conn构造方法
func NewConn(target string) *Conn {
	return &Conn{
		Id:     rand.Int63(),
		Target: target,
		Status: ON,
	}
}

func (c *Conn) getStatus() int {
	return c.Status
}

type ConnPool struct {
	sync.Pool
}

func GetPool(target string) (*ConnPool, error) {
	return &ConnPool{
		Pool: sync.Pool{
			New: func() interface{} {
				return NewConn(target)
			},
		},
	}, nil
}

// pool get
func (c *ConnPool) Get() *Conn {
	conn := c.Pool.Get().(*Conn)
	if conn.getStatus() == OFF {
		conn = c.Pool.New().(*Conn)
	}
	return conn
}

// pool put
func (c *ConnPool) Put(conn *Conn) {
	if conn.getStatus() == OFF {
		return
	}
	c.Pool.Put(conn)
}
